﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SdmxMl.Common;
using SdmxMl.Excel;

namespace SasPlugIn.DB
{
    public abstract class DbTable
    {
       #region Constantes

        protected const int ID_DEFAULT_LEN = 30;
        protected const int NAME_DEFAULT_LEN = 256;
        protected const int DESCRIPTION_DEFAULT_LEN = 2000;
        protected const string INTERNATIONALIZED_NAME_PREFIX = "Name_";
        protected const string INTERNATIONALIZED_DESCR_PREFIX = "Desc_";

        public const string LEVEL_COL_NAME = "Lev"; //Note: 'Level' is a key reserved in Oracle
        public const string CODE_COL_NAME = "Code";
        public const string PARENT_COL_NAME = "Parent";

        #endregion


        #region Internal Members

        /// <summary> Column list for SAS Table</summary>
        protected DbColumnList columns;

        /// <summary> SDMX maintenable artefact to present as table</summary>
        protected Artefact artefact;

        /// <summary> SDMX Extended information inventory (for artefact embedded items)</summary>
        protected AnnotationInventory anInventory;

        protected List<RowValues> DataRows;

        #endregion

        #region Properties

        /// <summary> Table name in DB</summary>
        public string Name { get; set; }

        /// <summary> Table prefix in DB</summary>
        public string Prefix { get; private set; }

        /// <summary>Interface to Columns</summary>
        public IList<DbColumn> Columns { get { return columns.Columns; } }

        /// <summary>Interface to Rows</summary>
        public IList<RowValues> Rows { get { return this.DataRows.AsReadOnly(); } }


        #endregion

        #region Constructor


        /// <summary> C'tor with table prefix and table name </summary>
        /// <param name="tableName">SAS table name</param>
        /// <param name="tablePrefix">Prefix before tableName Like: Meta.tableName</param>
        public DbTable(Artefact maintenableArtefact, AnnotationInventory anInv, string tableName, string tablePrefix)
        {
            columns = new DbColumnList();
            artefact = maintenableArtefact;
            anInventory = anInv;
            Name = tableName;
            Prefix = tablePrefix;
            DataRows = new List<RowValues>();

        }

        #endregion

        protected void Create()
        {
            CreateColumns();
            FillData();
        }

        #region Abstract Methods

        /// <summary>
        /// Fill Header columns according to table to create
        /// </summary>
        protected abstract void CreateColumns();

        /// <summary>
        /// Fill Data as a list of Row values
        /// </summary>
        protected abstract void FillData();

        #endregion

        protected void AddRowData(RowValues rowVal)
        {
            if (rowVal.Count != columns.Count)
                throw new ApplicationException("Invalid column count for datas in table " + Name);

            DataRows.Add(rowVal);
        }

        #region Annotations helpers

        /// <summary>
        /// Completes header with Annotations header info
        /// </summary>
        /// <param name="sb">the command builder</param>
        protected void GenAnnotationColumns()
        {
            if (anInventory != null && anInventory.Dico.Count > 0)
            {
                // For each annotation, 6 columns ANN_TYPE, ANN_TITLE, ALNN_TEXT_lg.., ANN_URN
                foreach (KeyValuePair<string, AnnotationCount> kvp in anInventory.Dico)
                {
                    // here check if selected annot
                    if (anInventory.IsSelectedAnnot(kvp.Value.Annot.Type) == false)
                        continue;

                    // For max instances encountered
                    for (int i = 0; i < kvp.Value.Count; i++)
                    {
                        string detail = string.Empty;
                        string instanceCount = string.Empty;
                        string annType = kvp.Value.Annot.Type.Replace(" ", "_");
                        if (kvp.Value.Count > 1)
                            instanceCount = string.Format("_{0}", i + 1);
                        if (kvp.Value.HasTitle)
                        {
                            columns.Add(new DbColumn(annType + instanceCount + "_Title", 80));
                            detail = "_Text";
                        }

                        if (kvp.Value.Internationalized)
                        {
                            foreach (string lg in SdmxMl.Common.LangSupport.SupportedLanguages)
                            {
                                columns.Add(new DbColumn(annType + instanceCount + detail + "_" + lg, DESCRIPTION_DEFAULT_LEN));
                            }
                        }
                        else
                        {
                            columns.Add(new DbColumn(annType + instanceCount + detail, DESCRIPTION_DEFAULT_LEN));
                        }
                        if (kvp.Value.HasUrn)
                        {
                            columns.Add(new DbColumn(annType + instanceCount + "_Url", 200));
                        }
                    }
                }
            }

        }

        /// <summary>
        /// Add value of annotations in data row to insert in table
        /// </summary>
        /// <param name="rowValues">list where to add values </param>
        /// <param name="annotationList">list of annotations for current row</param>
        protected void AddAnnotations(RowValues rowValues, AnnotationList annotationList)
        {
            if (anInventory == null)
                return;

            // For each annotation, 6 columns ANN_TYPE, ANN_TITLE, ALNN_TEXT_lg..
            foreach (KeyValuePair<string, AnnotationCount> kvp in anInventory.Dico)
            {
                // here check if selected annot
                if (anInventory.IsSelectedAnnot(kvp.Value.Annot.Type) == false)
                    continue;

                for (int i = 0; i < kvp.Value.Count; i++)
                {
                    Annotation a = annotationList.GetAnnotationType(kvp.Value.Annot.Type, i + 1);
                    if (a != null)
                    {
                        if (kvp.Value.HasTitle)
                            rowValues.Add(a.Title);

                        if (kvp.Value.Internationalized)
                        {
                            foreach (string lg in SdmxMl.Common.LangSupport.SupportedLanguages)
                                rowValues.Add(a.Text.GetIfDefinedForLanguage(lg));
                        }
                        else
                            rowValues.Add(a.Text.GetFirst());

                        if (kvp.Value.HasUrn)
                            rowValues.Add(a.Url != null ? a.Url.ToString() : string.Empty);
                    }
                    else // Null annotation, fill with empty
                    {
                        if (kvp.Value.HasTitle)
                            rowValues.Add(string.Empty);


                        if (kvp.Value.Internationalized)
                        {
                            foreach (string lg in SdmxMl.Common.LangSupport.SupportedLanguages)
                                rowValues.Add(string.Empty);
                        }
                        else
                            rowValues.Add(string.Empty);

                        if (kvp.Value.HasUrn)
                            rowValues.Add(string.Empty);
                    }
                }
            }
        }

        #endregion

    }

    public class RowValues : List<string>
    {
        public RowValues() : base() { }
        public RowValues(int capacity) : base(capacity) { }
    }
}
